home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Utilities / System / FKey / FKeys / tsv4.0.2 / src / Quik FKEY Installer.c next >
C/C++ Source or Header  |  1992-05-31  |  15KB  |  733 lines

  1. /* Quik FKEY Installer.c ©1992 by Mike Gleason Jr. */
  2.  
  3. #ifndef nil
  4. #    define nil                        ((void *) 0)
  5. #endif
  6.  
  7. #ifndef __PACKAGES__
  8. #    include <Packages.h>
  9. #endif
  10.  
  11. #define appleID                     400
  12.  
  13. #define fileID                        401
  14. #define        tryItItem                1
  15. #define     systemItem                3
  16. #define     suitcaseItem            4
  17. #define        removeSystemItem        6
  18. #define        removeSuitItem            7
  19. #define     quitItem                 9
  20.  
  21. #define editID                        402
  22.  
  23. #define SystemResFile                0
  24.  
  25. #define rAboutALRT                    129
  26. #define rStrList                    128
  27. #define rAboutFkeyDLOG                130
  28. #define rFkeyAboutTxt                128
  29.  
  30. #define infoW                        492
  31. #define infoH                        20
  32. #define infoM                        10
  33.  
  34. #define kExistingRsrc                99
  35.  
  36. WindowPtr                            gMsgWindow;
  37. Boolean                                gHasWaitNextEvent;
  38. SysEnvRec                            gMac;
  39. short                                gID;
  40. Str255                                gName;
  41. Handle                                gFkey, gFkeyAboutTxt;
  42. long                                gFkeyAboutTxtSize;
  43. CursHandle                            gWatch;
  44.  
  45. void             main(void);
  46. void             InitMacintosh(void);
  47. void             SetUpMenus(void);
  48. short             HandleEvent(void);
  49. void             HandleMouseDown(EventRecord *theEvent);
  50. void             HandleMenu (long mSelect);
  51. void            Message(unsigned char *str, long delay, Boolean killWhenDone);
  52. unsigned char    *pStrcat(unsigned char *s, register unsigned char *t);
  53. unsigned char    *pStrcpy(register unsigned char *s, register unsigned char *t);
  54. OSErr             SFGet(Str255 name, short *vref, long *dirid);
  55. Boolean         SFPut(Str255 name);
  56. void            Install(Boolean useSystemFile);
  57. OSErr            SFSystemDirectory(void);
  58. OSErr            SFDirID(short wd, short *volume, long *folder);
  59. short            CopyResource(short src, short dst, ResType type, short srcID, short dstID);
  60. void            About(void);
  61. void            Remove(Boolean useSystemFile);
  62. short            OpenDestFile(void);
  63. pascal Boolean    ResourceFilesOnly(ParmBlkPtr p);
  64. void            CloseMessage(void);
  65. short            KillOld(short dstResFile);
  66. void            TryIt(void);
  67. void            AboutFKEY(void);
  68. pascal void        AboutTxtUserItem(DialogPtr d, short itemNum);
  69.  
  70.  
  71.  
  72. pascal void AboutTxtUserItem(DialogPtr d, short itemNum)
  73. {
  74.     Handle                itemH;
  75.     short                itemType, a, b;
  76.     Rect                itemR;
  77.  
  78.     SetPort(d);
  79.     a = d->txFont;  b = d->txSize;
  80.     if (RealFont(times, 12))
  81.         TextFont(times);
  82.     else {
  83.         TextFont(geneva);
  84.         TextSize(9);
  85.     }
  86.     GetDItem(d, itemNum, &itemType, &itemH, &itemR);
  87.     HLock(gFkeyAboutTxt);
  88.     TextBox(*gFkeyAboutTxt, gFkeyAboutTxtSize, &itemR, teJustLeft);
  89.     HUnlock(gFkeyAboutTxt);
  90.     TextFont(a);   TextSize(b);
  91. }    /* AboutTxtUserItem */
  92.  
  93.  
  94.  
  95.  
  96. void AboutFKEY(void)
  97. {
  98.     DialogPtr            dptr;
  99.     Handle                itemH;
  100.     short                itemType, itemHit;
  101.     Rect                itemR;
  102.  
  103.     if (dptr = GetNewDialog(rAboutFkeyDLOG, nil, (WindowPtr) -1)) {
  104.         SetPort(dptr);
  105.         GetDItem(dptr, 2, &itemType, &itemH, &itemR);
  106.         SetDItem(dptr, 2, itemType, (Handle) AboutTxtUserItem, &itemR);
  107.  
  108.         ShowWindow(dptr);
  109.         SelectWindow(dptr);
  110.  
  111.         /* Make a default button's thick outline: */
  112.         GetDItem(dptr, 1, &itemType, &itemH, &itemR);
  113.         InsetRect(&itemR, -4, -4);
  114.         PenSize(3, 3);
  115.         FrameRoundRect(&itemR, 16, 16);
  116.         PenNormal();
  117.  
  118.         InitCursor();
  119.         do {
  120.             ModalDialog(nil, &itemHit);
  121.         } while (itemHit != 1);
  122.         DisposDialog(dptr);
  123.     }
  124. }    /* AboutFKEY */
  125.  
  126.  
  127.  
  128. void main(void)
  129. {
  130.     OSType        type;
  131.  
  132.     InitMacintosh();
  133.  
  134.     gMsgWindow = nil;
  135.     if (gFkeyAboutTxt = Get1Resource('TEXT', rFkeyAboutTxt))
  136.         gFkeyAboutTxtSize = SizeResource(gFkeyAboutTxt);
  137.     gFkey = Get1IndResource('FKEY', 1);
  138.     if (!gFkey)
  139.         ExitToShell();
  140.     GetResInfo(gFkey, &gID, &type, gName);
  141.     if (!*gName)
  142.         pStrcpy(gName, "\pUntitled");
  143.     gWatch = (CursHandle) RGetResource('CURS', watchCursor);
  144.     SetUpMenus();
  145.     About();
  146.     HandleEvent();
  147. }    // main
  148.  
  149.  
  150.  
  151.  
  152. void InitMacintosh(void)
  153. {
  154.     MaxApplZone();
  155.     
  156.     InitGraf(&thePort);
  157.     InitFonts();
  158.     FlushEvents(everyEvent, 0);
  159.     InitWindows();
  160.     InitMenus();
  161.     TEInit();
  162.     InitDialogs(0L);
  163.     InitCursor();
  164.     SysEnvirons(1, &gMac);
  165.     
  166. #define    WNETrapNum        0x60    /* Trap number of WaitNextEvent() */
  167. #define    UnImplTrapNum    0x9F    /* Trap number "unimplemented trap" */
  168.  
  169.     gHasWaitNextEvent =  NGetTrapAddress(WNETrapNum, ToolTrap) !=
  170.         NGetTrapAddress(UnImplTrapNum, ToolTrap);
  171. }    // InitMacintosh
  172.  
  173.  
  174.  
  175.  
  176. void SetUpMenus(void)
  177. {
  178.     MenuHandle mh;
  179.     unsigned char str[256];
  180.  
  181.     InsertMenu(mh = NewMenu(appleID, "\p\024"), 0);
  182.         pStrcpy(str, "\pAbout Quick FKEY Installer…;");
  183.         if (gFkeyAboutTxt) {
  184.             pStrcat(str, "\pAbout ");
  185.             pStrcat(str, gName);
  186.             pStrcat(str, "\p…");
  187.         }
  188.         AppendMenu(mh, str);
  189.         AddResMenu(mh, 'DRVR');
  190.  
  191.     InsertMenu(mh = NewMenu(fileID, "\pFile"), 0);
  192.         pStrcpy(str, "\pTry ");
  193.         pStrcat(str, gName);
  194.         pStrcat(str, "\p/J;-)");
  195.         AppendMenu(mh, str);
  196.         AppendMenu(mh, "\pInstall in System File;Install in a “Suitcase” File;(-;Remove from System File;Remove from “Suitcase” File;(-;Quit/Q");
  197.             
  198.     DrawMenuBar();    
  199. }    // SetUpMenus
  200.  
  201.  
  202.  
  203.  
  204. short HandleEvent(void)
  205. {
  206.     short            ok, ch;
  207.     EventRecord        theEvent;
  208.     
  209.     while (1) {
  210.         InitCursor();
  211.         if ( gHasWaitNextEvent ) {
  212.             ok = WaitNextEvent(everyEvent, &theEvent, 90L, nil);
  213.         } else {
  214.             SystemTask();
  215.             ok = GetNextEvent(everyEvent, &theEvent);
  216.         }
  217.         
  218.         if (ok)
  219.             switch (theEvent.what) {
  220.                 case mouseDown:
  221.                     HandleMouseDown(&theEvent);
  222.                     break;
  223.                     
  224.                 case keyDown: 
  225.                 case autoKey:
  226.                     ch = (theEvent.message & charCodeMask);
  227.                     if ((theEvent.modifiers & cmdKey) != 0)
  228.                         HandleMenu(MenuKey(ch));
  229.                     break;            
  230.             }
  231.     }
  232. } /* HandleEvent */
  233.  
  234.  
  235.  
  236.  
  237. void HandleMouseDown(EventRecord *theEvent)
  238. {
  239.     WindowPtr    theWindow;
  240.     short        windowCode = FindWindow (theEvent->where, &theWindow);
  241.     
  242.     switch (windowCode) {
  243.         case inSysWindow: 
  244.             SystemClick (theEvent, theWindow);
  245.             break;
  246.             
  247.         case inMenuBar:
  248.             HandleMenu(MenuSelect(theEvent->where));
  249.     }
  250. }    /* HandleMouseDown */
  251.  
  252.  
  253.  
  254.  
  255.  
  256. void HandleMenu (long mSelect)
  257. {
  258.     short            menuID = HiWord(mSelect);
  259.     short            menuItem = LoWord(mSelect);
  260.     unsigned char    name[256];
  261.     GrafPtr            savePort;
  262.     WindowPeek        frontWindow;
  263.     
  264.     HiliteMenu(0);
  265.     switch (menuID) {  
  266.         case appleID:          
  267.             GetPort(&savePort);
  268.             GetItem(GetMHandle(appleID), menuItem, name);
  269.             if (menuItem > 2)
  270.                 OpenDeskAcc(name);
  271.             else {
  272.                 if (menuItem == 1)
  273.                     About();
  274.                 else
  275.                     AboutFKEY();
  276.             }
  277.             SetPort(savePort);
  278.             break;
  279.       
  280.         case fileID:
  281.             switch (menuItem) {
  282.                 case tryItItem:
  283.                     TryIt();
  284.                     break;
  285.  
  286.                 case systemItem:
  287.                     Install(true);
  288.                     break;          
  289.                     
  290.                  case suitcaseItem:
  291.                         Install(false);
  292.                         break;
  293.                         
  294.                 case removeSystemItem:
  295.                     Remove(true);
  296.                     break;
  297.                 
  298.                 case removeSuitItem:
  299.                     Remove(false);
  300.                     break;
  301.                     
  302.                 case quitItem:
  303.                     ExitToShell();
  304.                     break;
  305.             }
  306.             break;                
  307.     }    /* end of menu numbers  */
  308. }    // HandleMenu
  309.  
  310.  
  311.  
  312.  
  313. void TryIt(void)
  314. {
  315.     typedef void    (**ProcHandle)(void);
  316.     SignedByte        state;
  317.     ProcHandle        p;
  318.     Str255            s = "\pRunning “";
  319.  
  320.     ResLoad = true;
  321.     p = (ProcHandle) Get1IndResource('FKEY', 1);
  322.     if (p) {
  323.         if (!*p)
  324.             Message("\pCouldn't load the FKEY!", 180L, true);
  325.         else {
  326.             state = HGetState((Handle) p);
  327.             HLock((Handle) p);
  328.             HNoPurge((Handle) p);
  329.             pStrcat(s, gName);
  330.             pStrcat(s, "\p…”");
  331.             Message(s, 45L, false);
  332.             (**p)();
  333.             HSetState((Handle) p, state);
  334.             CloseMessage();
  335.         }
  336.     } else
  337.         Message("\pCouldn't find the FKEY in this installer!", 180L, true);
  338. }    // TryIt
  339.  
  340.  
  341.  
  342.  
  343. short KillOld(short dstResFile)
  344. {
  345.     short i, j, del, id, old;
  346.     OSType type;
  347.     Handle h;
  348.     Str255 killName, str;
  349.  
  350.     old = CurResFile();
  351.     GetIndString(killName, rStrList, 1);
  352.     UseResFile(dstResFile);
  353.     
  354.     // First, delete any duplicates of this FKEY.
  355.     if ((h = Get1NamedResource('FKEY', gName))) {
  356.         RmveResource(h);
  357.         del++;    
  358.     }
  359.     
  360.     // Next delete all FKEYs whose name begins with 'killName,'
  361.     // so if we have killName="MyFkey", we can delete "MyFkey 1.2", etc.
  362.     j = Count1Resources('FKEY');
  363.     for (i=1, del=0; i<=j; i++) {
  364.         h = Get1IndResource('FKEY', i);
  365.         GetResInfo(h, &id, &type, str);
  366.         if (ResErr || *str < *killName)
  367.             continue;
  368.         else if (*str > *killName)
  369.             *str = *killName;
  370.         if (IUEqualString(str, killName) == 0) {
  371.             RmveResource(h);
  372.             del++;    
  373.         }
  374.     }
  375.     if (del > 0)
  376.         UpdateResFile(dstResFile);
  377.     UseResFile(old);
  378.     return del;
  379. }    // KillOld
  380.  
  381.  
  382.  
  383.  
  384. short OpenDestFile(void)
  385. {
  386.     Str255 destName;
  387.     short vref, a;
  388.     long dirid;
  389.  
  390.     (void) SFSystemDirectory();
  391.     if (SFGet(destName, &vref, &dirid))
  392.         return (-1);
  393.     a = HOpenResFile(vref, dirid, destName, fsRdWrShPerm);
  394.     if (ResErr)
  395.         a = -1;
  396.     return a;
  397. }    // OpenDestFile
  398.  
  399.  
  400.  
  401.  
  402. void Remove(Boolean useSystemFile)
  403. {
  404.     short destResFile, del;
  405.  
  406.     if (useSystemFile) {
  407.         SetCursor(*gWatch);
  408.         del = KillOld(SystemResFile);
  409.     } else {
  410.         Message("\pSelect the file you want the FKEY removed from:", 0L, false);
  411.         destResFile = OpenDestFile();
  412.         if (destResFile != -1) {
  413.             SetCursor(*gWatch);
  414.             del = KillOld(destResFile);
  415.             CloseResFile(destResFile);
  416.         } else
  417.             goto x;
  418.     }
  419.     
  420.     if (del)
  421.         Message("\pRemoved successfully.", 120L, true);
  422.     else
  423.         Message("\pNo FKEYs removed from this file.", 120L, true);
  424. x:    CloseMessage();
  425. }    // Remove
  426.  
  427.  
  428.  
  429.  
  430. void Install(Boolean useSystemFile)
  431. {
  432.     OSErr            err;
  433.     short            destResFile, myResFile, dstID, i, j;
  434.     unsigned char    msg[256] = "\pInstalled “", tmp[8];
  435.  
  436.     myResFile = CurResFile();
  437.     
  438.     if (useSystemFile)
  439.         destResFile = SystemResFile;
  440.     else {
  441.         Message("\pSelect the file you want to install the FKEY in:", 0L, false);
  442.         destResFile = OpenDestFile();
  443.         if (destResFile == -1)
  444.             goto d2;
  445.     }
  446.     
  447.     SetCursor(*gWatch);
  448.  
  449.     // Delete obselete versions of the same FKEY first.
  450.     if (KillOld(destResFile))
  451.         Message("\pDeleted old version.", 60L, false);
  452.  
  453.     // Try copying the resource verbatim. 
  454.     dstID = gID;
  455.     err = CopyResource(myResFile, destResFile, 'FKEY', gID, dstID);
  456.     if (err < 0) {
  457.         Message("\pError occurred while copying the FKEY.", 180L, true);
  458.         goto done;
  459.     } else if (err == kExistingRsrc) {
  460.         // There already is an FKEY with id == gID.
  461.         // Try to install in another slot.
  462.  
  463.         for (i=5; i<=10; i++) {
  464.             if (i == 10)
  465.                 dstID = 0;
  466.             else
  467.                 dstID = i;
  468.             err = CopyResource(myResFile, destResFile, 'FKEY', gID, dstID);
  469.             if (err && err != kExistingRsrc) {
  470.                 Message("\pError occurred while copying the FKEY.", 180L, true);
  471.                 goto done;
  472.             } else if (err == noErr)  {
  473.                 /* Hey! We found a slot for the fkey to fit. */
  474.                 /* Message */
  475.                 break; /* done, finally! */
  476.             }    /* end if we installed in an alternate slot */
  477.         }        /* end looping for empty slots */
  478.     }            /* end if our preferred slot was filled */
  479.         
  480.     if (err)
  481.         Message("\pSorry, there are already too many FKEYs in this file.", 180L, true);
  482.     else {
  483.         pStrcat(msg, gName);
  484.         pStrcat(msg, "\p” okay. Type command-shift-");
  485.         NumToString((long)dstID, tmp);
  486.         pStrcat(msg, tmp);
  487.         pStrcat(msg, "\p to run it. <Click>");
  488.         Message(msg, 120L, true);
  489.     }    /* end notifying the user of a successful install */
  490.  
  491. done:
  492.     UseResFile(myResFile);
  493.     if (destResFile != SystemResFile)
  494.         CloseResFile(destResFile);
  495. d2:    CloseMessage();
  496. }    // Install
  497.  
  498.  
  499.  
  500.  
  501. short CopyResource(short src, short dst, ResType type, short srcID, short dstID)
  502. {
  503.     Handle    RSRC = 0L, h;
  504.     short    oldResFile;
  505.     OSErr    err;
  506.     Str255    resname;
  507.     
  508.     oldResFile = CurResFile();
  509.     
  510.     UseResFile(dst);
  511.     RSRC = Get1Resource(type, dstID);
  512.                             /*    see if we have a resource with
  513.                                 the same id already present. */
  514.     err = ResError();
  515.     if (!err && RSRC) {
  516.         ReleaseResource(RSRC);
  517.         return (kExistingRsrc);
  518.     }
  519.     
  520.     UseResFile(src);
  521.     
  522.     RSRC = Get1Resource(type, srcID);
  523.                             /* load the source rsrc */
  524.     if (err = ResError()) goto heave;
  525.     
  526.     GetResInfo(RSRC, &srcID, &type, resname);
  527.                             /*    we need to do this to get the 
  528.                                 resource's name, if any */
  529.     if (err = ResError()) goto heave;
  530.     
  531.     UseResFile(dst);
  532.     
  533.     h = RSRC;
  534.     HandToHand(&h);
  535.     if (!h) goto heave;
  536.  
  537.     DetachResource(h);    /*    have to detach it to make a copy */
  538.     AddResource(h, type, dstID, resname);
  539.                             /*    now actually copy it */
  540.     if (err = ResError()) goto heave;
  541.         
  542.     ChangedResource(h);    /*    mark it as changed */
  543.     if (err = ResError()) goto heave;
  544.     
  545.     UpdateResFile(dst);        /*    write out the resource file */
  546.     err = ResError();
  547.     
  548. heave:
  549.     UseResFile(oldResFile);
  550.     return (err);
  551. }    /* CopyResource */
  552.  
  553.  
  554.  
  555.  
  556. void CloseMessage(void)
  557. {
  558.     if (gMsgWindow) {
  559.         DisposeWindow(gMsgWindow);
  560.         gMsgWindow = nil;
  561.     }
  562. }    // CloseMessage
  563.  
  564.  
  565.  
  566.  
  567. void Message(unsigned char *str, long delay, Boolean killWhenDone)
  568. {
  569.     Rect            r;
  570.     short            dy, quikMask = keyDownMask + autoKeyMask + mDownMask;
  571.     EventRecord        E;
  572.  
  573.     if (!gMsgWindow) {
  574.         SetRect(
  575.             &r,
  576.             infoM,
  577.             MBarHeight + infoM, 
  578.             infoM + infoW,
  579.             MBarHeight + infoM + infoH
  580.         );
  581.         gMsgWindow = NewWindow(
  582.             0L,                 /* window's storage ptr, 0L usually */
  583.             &r,                    /* the window's rect */
  584.             "\pWindow Title",    /* the window's title */
  585.             FALSE,                /* is the window initially visible? */
  586.             dBoxProc,            /* type of window */
  587.             (WindowPtr) -1L,    /* front of which window, -1L = all */
  588.             0,                    /* has a go away box? */
  589.             0                    /* window refnum */
  590.         );
  591.         
  592.         if (gMsgWindow) {
  593.             ShowWindow(gMsgWindow);
  594.             SelectWindow(gMsgWindow);
  595.         } else
  596.             return;
  597.     }
  598.     
  599.     SetPort(gMsgWindow);
  600.     EraseRect(&gMsgWindow->portRect);
  601.     TextFont(times);
  602.     TextSize(12);
  603.     MoveTo((infoW - StringWidth(str)) / 2, 14);
  604.     DrawString(str);
  605.  
  606. /*    delay until the mouse button is pressed, a key is
  607.     pressed, or 'TixToDelay' ticks has elapsed. This is a
  608.     better way than testing Button() all the time, 'cuz
  609.     it removes the event from the queue (otherwise when
  610.     you clicked it could select a background application */
  611.     
  612.     if (delay > 0L) {
  613.         delay += Ticks;
  614.         
  615.         while (Ticks < delay) {
  616.             if (GetNextEvent(quikMask, &E))
  617.                 break;
  618.             SystemTask();
  619.         }
  620.     }
  621.  
  622.     ValidRect(&gMsgWindow->portRect);
  623.     if (killWhenDone)
  624.         CloseMessage();
  625. }    // Message
  626.  
  627.  
  628.  
  629.  
  630. unsigned char *pStrcat(unsigned char *s, register unsigned char *t)
  631. {
  632.     register unsigned char *s2;
  633.     register short tLen;
  634.  
  635.     s2 = s + *s;
  636.     *s += (tLen = *t);
  637.     for (++tLen; --tLen; s2[tLen] = t[tLen]);
  638.     return (s);
  639. }    /* pStrcat */
  640.  
  641.  
  642.  
  643.  
  644. unsigned char *pStrcpy(register unsigned char *s, register unsigned char *t)
  645. {
  646.     register short    tLen;
  647.  
  648.     for (tLen = *t + 1; tLen--; s[tLen] = t[tLen]);
  649.     return (s);
  650. }    /* pStrcpy */
  651.  
  652.  
  653.  
  654.  
  655. pascal Boolean ResourceFilesOnly(ParmBlkPtr p)
  656. {
  657.     return (!(p->fileParam.ioFlRLgLen > 0L));
  658.     /* return FALSE if you want a file to be shown in the list... */
  659. }    /* ResourceFilesOnly */
  660.  
  661.  
  662.  
  663.  
  664. OSErr SFGet(Str255 name, short *vref, long *dirid)
  665. {
  666.     SFReply        reply;
  667.     SFTypeList    typeList;
  668.     Point        location = {0x40,0x40};
  669.     OSErr        err;
  670.     
  671.     location.v = MBarHeight + infoH + (3*infoM);
  672.     
  673.     SFGetFile(
  674.         location,                    /* location */
  675.         "\pSpace for Rent",            /* vestigial string */
  676.         ResourceFilesOnly,            /* fileFilter */
  677.         -1,                            /* numtypes; -1 means all */
  678.         &typeList,                    /* array to types to show */
  679.         nil,                        /* dlgHook */
  680.         &reply                        /* record for returned values */
  681.     );                    
  682.     
  683.     if (reply.good) {
  684.         pStrcpy(name, reply.fName);
  685.         if (err = SetVol(name, reply.vRefNum))
  686.             return (err);
  687.         *vref = -SFSaveDisk;
  688.         *dirid = CurDirStore;
  689.         return (noErr);
  690.     } else
  691.         return (1);    /* nothing selected */
  692. }    /* SFGet */
  693.  
  694.  
  695.  
  696.  
  697. OSErr SFSystemDirectory(void)
  698. {
  699.     WDPBRec            pb;
  700.     SysEnvRec        theWorld;
  701.     Str255            name;
  702.     OSErr            err;
  703.  
  704.     if (err = SysEnvirons(1, &theWorld))
  705.         return (err);
  706.  
  707.     pb.ioNamePtr = (StringPtr) name;
  708.     pb.ioCompletion = 0L;
  709.     pb.ioVRefNum = theWorld.sysVRefNum;
  710.     pb.ioWDIndex = 0;
  711.     pb.ioWDProcID = 0;
  712.     pb.ioWDVRefNum = 0;
  713.     if ((err = PBGetWDInfo(&pb,false)))
  714.         return (err);
  715.  
  716.     CurDirStore = pb.ioWDDirID;
  717.     SFSaveDisk = -pb.ioWDVRefNum;
  718.         /* on the next SFGetFile (…) it will open in the System Folder. */
  719.         
  720.     return (noErr);
  721. }    /* SFSystemDirectory */
  722.  
  723.  
  724.  
  725.  
  726. void About(void)
  727. {
  728.     ParamText(gName, nil, nil, nil);
  729.     (void) Alert(rAboutALRT, nil);
  730. }    /* About */
  731.  
  732. /* eof */
  733.